package com.baymax.study.tuLing.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

/**
 * @author baymax
 * @since 2025-06-27
 */
public class NioNonBlockDemo1_Selector {
    public static final int PORT = 60001;

    static class Server {
        public static void main(String[] args) throws Exception {
            // 1.创建Selector，用来管理所有的 Channel
            Selector selector = Selector.open();

            ServerSocketChannel ssc = ServerSocketChannel.open();
            ssc.configureBlocking(false);
            ssc.bind(new InetSocketAddress(PORT));
            // 2.将ServerSocketChannel 注册到 Selector，监听 accept 事件
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //SelectionKey selectionKey = ssc.register(selector, 0, null);
            //selectionKey.interestOps(SelectionKey.OP_ACCEPT);
            System.out.println("服务器启动成功");

            while (true) {
                // 3.获取所有注册的 key，没有事件发生，则会阻塞线程；有事件发生，线程才会继续往下执行
                // selector 中如果有事件未处理，则不会阻塞
                selector.select();
                // 4.处理事件
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    iterator.remove();
                    // 5.区分处理对应的事件
                    if (key.isAcceptable()) { // 5.1如果是accept事件（连接事件）
                        System.out.println("连接成功...");
                        ServerSocketChannel ssc2 = (ServerSocketChannel) key.channel();
                        SocketChannel sc = ssc2.accept();
                        sc.configureBlocking(false);
                        // 将SocketChannel注册到selector上，并且关注read事件
                        //sc.register(selector, SelectionKey.OP_READ);
                        SelectionKey selectionKey = sc.register(selector, 0, null);
                        selectionKey.interestOps(SelectionKey.OP_READ);
                    }
                    if (key.isReadable()) { // 5.2如果是read事件（读数据事件）
                        System.out.println("开始读取数据...");
                        SocketChannel sc = (SocketChannel) key.channel();
                        try {
                            ByteBuffer buffer = ByteBuffer.allocate(16);
                            int readBytes = sc.read(buffer);
                            if (readBytes == -1) { // 读到-1字节，说明对端链路已经关闭
                                System.out.println("对端链路已经关闭");
                                key.cancel();
                                sc.close();
                            } else {
                                buffer.flip();
                                System.out.println(Charset.defaultCharset().decode(buffer));
                            }
                        } catch (IOException e) {
                            // 异常断开
                            key.cancel();
                            sc.close();
                        }
                    }
                }
            }
        }
    }

    static class Client {
        public static void main(String[] args) throws Exception {
            SocketChannel sc = SocketChannel.open();
            sc.connect(new InetSocketAddress("127.0.0.1", PORT));
            System.out.println("连接成功");

            TimeUnit.SECONDS.sleep(2);
            sc.write(ByteBuffer.wrap("hello client".getBytes()));
            System.out.println("数据发送完毕");
            sc.close();
        }
    }
}
